#ifndef BONDERHEADCONFIG_H
#define BONDERHEADCONFIG_H

#include "configManager/configobject.h"
#include "configManager/configobjectarray.h"

class PickPlaceConfig : public ConfigObject
{
    Q_OBJECT

    Q_PROPERTY(
        double softlandingPickVel READ softlandingPickVel WRITE setSoftlandingPickVel NOTIFY softlandingPickVelChanged)
    Q_PROPERTY(double softlandingPickForce READ softlandingPickForce WRITE setSoftlandingPickForce NOTIFY
                   softlandingPickForceChanged)
    Q_PROPERTY(bool useFastSoftlandingPick READ useFastSoftlandingPick WRITE setUseFastSoftlandingPick NOTIFY
                   useFastSoftlandingPickChanged)
    Q_PROPERTY(int openVacuumDelayAfterStartSoftlanding READ openVacuumDelayAfterStartSoftlanding WRITE
                   setOpenVacuumDelayAfterStartSoftlanding NOTIFY openVacuumDelayAfterStartSoftlandingChanged)
    Q_PROPERTY(double softlandingPlaceVel READ softlandingPlaceVel WRITE setSoftlandingPlaceVel NOTIFY
                   softlandingPlaceVelChanged)
    Q_PROPERTY(double softlandingPlaceForce READ softlandingPlaceForce WRITE setSoftlandingPlaceForce NOTIFY
                   softlandingPlaceForceChanged)
    Q_PROPERTY(bool useFastSoftlandingPlace READ useFastSoftlandingPlace WRITE setUseFastSoftlandingPlace NOTIFY
                   useFastSoftlandingPlaceChanged)
    Q_PROPERTY(int delayBeforePick READ delayBeforePick WRITE setDelayBeforePick NOTIFY delayBeforePickChanged)
    Q_PROPERTY(int delayBeforePlace READ delayBeforePlace WRITE setDelayBeforePlace NOTIFY delayBeforePlaceChanged)
    Q_PROPERTY(int delayAfterSoftLandUpCmd READ delayAfterSoftLandUpCmd WRITE setDelayAfterSoftLandUpCmd NOTIFY
                   delayAfterSoftLandUpCmdChanged)
    Q_PROPERTY(int delayAfterSoftlandContact READ delayAfterSoftlandContact WRITE setDelayAfterSoftlandContact NOTIFY
                   delayAfterSoftlandContactChanged)
    Q_PROPERTY(int delayAfterOpenVacuum READ delayAfterOpenVacuum WRITE setDelayAfterOpenVacuum NOTIFY
                   delayAfterOpenVacuumChanged)
    Q_PROPERTY(int delayAfterCloseVacuum READ delayAfterCloseVacuum WRITE setDelayAfterCloseVacuum NOTIFY
                   delayAfterCloseVacuumChanged)
public:
    PickPlaceConfig(QObject *parent = nullptr) : ConfigObject(parent)
    {
        init();
    }

    double softlandingPickVel() const
    {
        return m_softlandingPickVel;
    }

    double softlandingPickForce() const
    {
        return m_softlandingPickForce;
    }

    bool useFastSoftlandingPick() const
    {
        return m_useFastSoftlandingPick;
    }

    double softlandingPlaceVel() const
    {
        return m_softlandingPlaceVel;
    }

    double softlandingPlaceForce() const
    {
        return m_softlandingPlaceForce;
    }

    int delayBeforePick() const
    {
        return m_delayBeforePick;
    }

    int delayBeforePlace() const
    {
        return m_delayBeforePlace;
    }

    int delayAfterSoftLandUpCmd() const
    {
        return m_delayAfterSoftLandUpCmd;
    }

    int delayAfterSoftlandContact() const
    {
        return m_delayAfterSoftlandContact;
    }

    int delayAfterOpenVacuum() const
    {
        return m_delayAfterOpenVacuum;
    }

    int delayAfterCloseVacuum() const
    {
        return m_delayAfterCloseVacuum;
    }

    int openVacuumDelayAfterStartSoftlanding() const
    {
        return m_openVacuumDelayAfterStartSoftlanding;
    }

    bool useFastSoftlandingPlace() const
    {
        return m_useFastSoftlandingPlace;
    }

public slots:
    void setSoftlandingPickVel(double softlandingPickVel)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_softlandingPickVel, softlandingPickVel))
            return;

        m_softlandingPickVel = softlandingPickVel;
        emit softlandingPickVelChanged(m_softlandingPickVel);
    }

    void setSoftlandingPickForce(double softlandingPickForce)
    {
        //   qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_softlandingPickForce, softlandingPickForce))
            return;

        m_softlandingPickForce = softlandingPickForce;
        emit softlandingPickForceChanged(m_softlandingPickForce);
    }

    void setUseFastSoftlandingPick(bool useFastSoftlandingPick)
    {
        if (m_useFastSoftlandingPick == useFastSoftlandingPick)
            return;

        m_useFastSoftlandingPick = useFastSoftlandingPick;
        emit useFastSoftlandingPickChanged(m_useFastSoftlandingPick);
    }

    void setSoftlandingPlaceVel(double softlandingPlaceVel)
    {
        //   qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_softlandingPlaceVel, softlandingPlaceVel))
            return;

        m_softlandingPlaceVel = softlandingPlaceVel;
        emit softlandingPlaceVelChanged(m_softlandingPlaceVel);
    }

    void setSoftlandingPlaceForce(double softlandingPlaceForce)
    {
        //    qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_softlandingPlaceForce, softlandingPlaceForce))
            return;

        m_softlandingPlaceForce = softlandingPlaceForce;
        emit softlandingPlaceForceChanged(m_softlandingPlaceForce);
    }

    void setDelayBeforePick(int delayBeforePick)
    {
        if (m_delayBeforePick == delayBeforePick)
            return;

        m_delayBeforePick = delayBeforePick;
        emit delayBeforePickChanged(m_delayBeforePick);
    }

    void setDelayBeforePlace(int delayBeforePlace)
    {
        if (m_delayBeforePlace == delayBeforePlace)
            return;

        m_delayBeforePlace = delayBeforePlace;
        emit delayBeforePlaceChanged(m_delayBeforePlace);
    }

    void setDelayAfterSoftLandUpCmd(int delayAfterSoftLandUpCmd)
    {
        if (m_delayAfterSoftLandUpCmd == delayAfterSoftLandUpCmd)
            return;

        m_delayAfterSoftLandUpCmd = delayAfterSoftLandUpCmd;
        emit delayAfterSoftLandUpCmdChanged(m_delayAfterSoftLandUpCmd);
    }

    void setDelayAfterSoftlandContact(int delayAfterSoftlandContact)
    {
        if (m_delayAfterSoftlandContact == delayAfterSoftlandContact)
            return;

        m_delayAfterSoftlandContact = delayAfterSoftlandContact;
        emit delayAfterSoftlandContactChanged(m_delayAfterSoftlandContact);
    }

    void setDelayAfterOpenVacuum(int delayAfterOpenVacuum)
    {
        if (m_delayAfterOpenVacuum == delayAfterOpenVacuum)
            return;

        m_delayAfterOpenVacuum = delayAfterOpenVacuum;
        emit delayAfterOpenVacuumChanged(m_delayAfterOpenVacuum);
    }

    void setDelayAfterCloseVacuum(int delayAfterCloseVacuum)
    {
        if (m_delayAfterCloseVacuum == delayAfterCloseVacuum)
            return;

        m_delayAfterCloseVacuum = delayAfterCloseVacuum;
        emit delayAfterCloseVacuumChanged(m_delayAfterCloseVacuum);
    }

    void setOpenVacuumDelayAfterStartSoftlanding(int openVacuumDelayAfterStartSoftlanding)
    {
        if (m_openVacuumDelayAfterStartSoftlanding == openVacuumDelayAfterStartSoftlanding)
            return;

        m_openVacuumDelayAfterStartSoftlanding = openVacuumDelayAfterStartSoftlanding;
        emit openVacuumDelayAfterStartSoftlandingChanged(m_openVacuumDelayAfterStartSoftlanding);
    }

    void setUseFastSoftlandingPlace(bool useFastSoftlandingPlace)
    {
        if (m_useFastSoftlandingPlace == useFastSoftlandingPlace)
            return;

        m_useFastSoftlandingPlace = useFastSoftlandingPlace;
        emit useFastSoftlandingPlaceChanged(m_useFastSoftlandingPlace);
    }

signals:
    void softlandingPickVelChanged(double softlandingPickVel);

    void softlandingPickForceChanged(double softlandingPickForce);

    void useFastSoftlandingPickChanged(bool useFastSoftlandingPick);

    void softlandingPlaceVelChanged(double softlandingPlaceVel);

    void softlandingPlaceForceChanged(double softlandingPlaceForce);

    void delayBeforePickChanged(int delayBeforePick);

    void delayBeforePlaceChanged(int delayBeforePlace);

    void delayAfterSoftLandUpCmdChanged(int delayAfterSoftLandUpCmd);

    void delayAfterSoftlandContactChanged(int delayAfterSoftlandContact);

    void delayAfterOpenVacuumChanged(int delayAfterOpenVacuum);

    void delayAfterCloseVacuumChanged(int delayAfterCloseVacuum);

    void openVacuumDelayAfterStartSoftlandingChanged(int openVacuumDelayAfterStartSoftlanding);

    void useFastSoftlandingPlaceChanged(bool useFastSoftlandingPlace);

private:
    double m_softlandingPickVel = 20;
    double m_softlandingPickForce = 0.01;
    bool m_useFastSoftlandingPick = true;
    double m_softlandingPlaceVel = 15;
    double m_softlandingPlaceForce = 0.01;
    int m_delayBeforePick = -1;
    int m_delayBeforePlace = -1;
    int m_delayAfterSoftLandUpCmd = 150;
    int m_delayAfterSoftlandContact = -1;
    int m_delayAfterOpenVacuum = -1;
    int m_delayAfterCloseVacuum = -1;
    int m_openVacuumDelayAfterStartSoftlanding = -1;
    bool m_useFastSoftlandingPlace = false;
};

class CameraOffset : public ConfigObject
{
    Q_OBJECT

    Q_PROPERTY(double x READ x WRITE setX NOTIFY xChanged)
    Q_PROPERTY(double y READ y WRITE setY NOTIFY yChanged)
    Q_PROPERTY(double theta READ theta WRITE setTheta NOTIFY thetaChanged)

public:
    Q_INVOKABLE CameraOffset(QObject *parent = nullptr) : ConfigObject(parent)
    {
        init();
    }

    double x() const
    {
        return m_x;
    }

    double y() const
    {
        return m_y;
    }

    double theta() const
    {
        return m_theta;
    }

public slots:
    void setX(double x)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_x, x))
            return;

        m_x = x;
        emit xChanged(m_x);
    }

    void setY(double y)
    {
        //     qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_y, y))
            return;

        m_y = y;
        emit yChanged(m_y);
    }

    void setTheta(double theta)
    {
        //     qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_theta, theta))
            return;

        m_theta = theta;
        emit thetaChanged(m_theta);
    }

signals:
    void xChanged(double x);

    void yChanged(double y);

    void thetaChanged(double theta);

private:
    double m_x = 0;
    double m_y = 0;
    double m_theta = 0;
};

class YZPos : public ConfigObject
{
    Q_OBJECT

    Q_PROPERTY(double yPos READ yPos WRITE setYPos NOTIFY yPosChanged)
    Q_PROPERTY(double zPos READ zPos WRITE setZPos NOTIFY zPosChanged)

public:
    YZPos(QObject *parent = nullptr) : ConfigObject(parent)
    {
        init();
    }

    void set(double y, double z)
    {
        setConfig("yPos", y);
        setConfig("zPos", z);
    }

    double yPos() const
    {
        return m_yPos;
    }
    double zPos() const
    {
        return m_zPos;
    }

public slots:
    void setYPos(double yPos)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_yPos, yPos))
            return;

        m_yPos = yPos;
        emit yPosChanged(m_yPos);
    }
    void setZPos(double zPos)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_zPos, zPos))
            return;

        m_zPos = zPos;
        emit zPosChanged(m_zPos);
    }

signals:
    void yPosChanged(double yPos);
    void zPosChanged(double zPos);

private:
    double m_yPos = 0;
    double m_zPos = 0;
};

class TwoDimensionCaliParameter : public ConfigObject
{
    Q_OBJECT

    Q_PROPERTY(double xStartAbsPos READ xStartAbsPos WRITE setXStartAbsPos NOTIFY xStartAbsPosChanged)
    Q_PROPERTY(double xEndAbsPos READ xEndAbsPos WRITE setXEndAbsPos NOTIFY xEndAbsPosChanged)
    Q_PROPERTY(int xStep READ xStep WRITE setXStep NOTIFY xStepChanged)
    Q_PROPERTY(double yStartRelPos READ yStartRelPos WRITE setYStartRelPos NOTIFY yStartRelPosChanged)
    Q_PROPERTY(double yEndRelPos READ yEndRelPos WRITE setYEndRelPos NOTIFY yEndRelPosChanged)
    Q_PROPERTY(int yStep READ yStep WRITE setYStep NOTIFY yStepChanged)
    Q_PROPERTY(double referencePointPrecisionX READ referencePointPrecisionX WRITE setReferencePointPrecisionX NOTIFY
                   referencePointPrecisionXChanged)
    Q_PROPERTY(double referencePointPrecisionY READ referencePointPrecisionY WRITE setReferencePointPrecisionY NOTIFY
                   referencePointPrecisionYChanged)
    Q_PROPERTY(int referencePointReachPrecisionMaxRetryTimes READ referencePointReachPrecisionMaxRetryTimes WRITE
                   setReferencePointReachPrecisionMaxRetryTimes NOTIFY referencePointReachPrecisionMaxRetryTimesChanged)

public:
    TwoDimensionCaliParameter(QObject *parent = nullptr) : ConfigObject(parent)
    {
        init();
    }

    double xStartAbsPos() const
    {
        return m_xStartAbsPos;
    }
    double xEndAbsPos() const
    {
        return m_xEndAbsPos;
    }

    int xStep() const
    {
        return m_xStep;
    }

    double yStartRelPos() const
    {
        return m_yStartRelPos;
    }

    double yEndRelPos() const
    {
        return m_yEndRelPos;
    }

    int yStep() const
    {
        return m_yStep;
    }

    double referencePointPrecisionX() const
    {
        return m_referencePointPrecisionX;
    }

    double referencePointPrecisionY() const
    {
        return m_referencePointPrecisionY;
    }

    int referencePointReachPrecisionMaxRetryTimes() const
    {
        return m_referencePointReachPrecisionMaxRetryTimes;
    }

public slots:
    void setXStartAbsPos(double xStartAbsPos)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_xStartAbsPos, xStartAbsPos))
            return;

        m_xStartAbsPos = xStartAbsPos;
        emit xStartAbsPosChanged(m_xStartAbsPos);
    }

    void setXEndAbsPos(double xEndAbsPos)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_xEndAbsPos, xEndAbsPos))
            return;

        m_xEndAbsPos = xEndAbsPos;
        emit xEndAbsPosChanged(m_xEndAbsPos);
    }

    void setXStep(int xStep)
    {
        if (m_xStep == xStep)
            return;

        if (xStep < 2)
        {
            qWarning() << tr("xStep must greater than 1!");
            emit xStepChanged(m_xStep);
            return;
        }
        m_xStep = xStep;
        emit xStepChanged(m_xStep);
    }

    void setYStartRelPos(double yStartRelPos)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_yStartRelPos, yStartRelPos))
            return;

        m_yStartRelPos = yStartRelPos;
        emit yStartRelPosChanged(m_yStartRelPos);
    }

    void setYEndRelPos(double yEndRelPos)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_yEndRelPos, yEndRelPos))
            return;

        m_yEndRelPos = yEndRelPos;
        emit yEndRelPosChanged(m_yEndRelPos);
    }

    void setYStep(int yStep)
    {
        if (m_yStep == yStep)
            return;

        if (yStep < 2)
        {
            qWarning() << tr("yStep must greater than 1!");
            emit yStepChanged(m_yStep);
            return;
        }
        m_yStep = yStep;
        emit yStepChanged(m_yStep);
    }

    void setReferencePointPrecisionX(double referencePointPrecisionX)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_referencePointPrecisionX, referencePointPrecisionX))
            return;

        m_referencePointPrecisionX = referencePointPrecisionX;
        emit referencePointPrecisionXChanged(m_referencePointPrecisionX);
    }

    void setReferencePointPrecisionY(double referencePointPrecisionY)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_referencePointPrecisionY, referencePointPrecisionY))
            return;

        m_referencePointPrecisionY = referencePointPrecisionY;
        emit referencePointPrecisionYChanged(m_referencePointPrecisionY);
    }

    void setReferencePointReachPrecisionMaxRetryTimes(int referencePointReachPrecisionMaxRetryTimes)
    {
        if (m_referencePointReachPrecisionMaxRetryTimes == referencePointReachPrecisionMaxRetryTimes)
            return;

        m_referencePointReachPrecisionMaxRetryTimes = referencePointReachPrecisionMaxRetryTimes;
        emit referencePointReachPrecisionMaxRetryTimesChanged(m_referencePointReachPrecisionMaxRetryTimes);
    }

signals:
    void xStartAbsPosChanged(double xStartAbsPos);
    void xEndAbsPosChanged(double xEndAbsPos);
    void xStepChanged(int xStep);
    void yStartRelPosChanged(double yStartRelPos);
    void yEndRelPosChanged(double yEndRelPos);
    void yStepChanged(int yStep);
    void referencePointPrecisionXChanged(double referencePointPrecisionX);
    void referencePointPrecisionYChanged(double referencePointPrecisionY);
    void referencePointReachPrecisionMaxRetryTimesChanged(int referencePointReachPrecisionMaxRetryTimes);

private:
    double m_xStartAbsPos = -3.1;
    double m_xEndAbsPos = 1.7;
    int m_xStep = 4;
    double m_yStartRelPos = -3;
    double m_yEndRelPos = 3;
    int m_yStep = 4;
    double m_referencePointPrecisionX = 0.015;
    double m_referencePointPrecisionY = 0.015;
    int m_referencePointReachPrecisionMaxRetryTimes = 3;
};

class BonderHeadConfig : public ConfigObject
{
    Q_OBJECT

    Q_PROPERTY(PickPlaceConfig *pickPlaceConfig READ pickPlaceConfig)

    Q_PROPERTY(double ltCaliGlassPrOffsetX READ ltCaliGlassPrOffsetX WRITE setLtCaliGlassPrOffsetX NOTIFY
                   ltCaliGlassPrOffsetXChanged)
    Q_PROPERTY(double ltCaliGlassPrOffsetY READ ltCaliGlassPrOffsetY WRITE setLtCaliGlassPrOffsetY NOTIFY
                   ltCaliGlassPrOffsetYChanged)
    Q_PROPERTY(double corCaliStartPos READ corCaliStartPos WRITE setCorCaliStartPos NOTIFY corCaliStartPosChanged)
    Q_PROPERTY(int corCaliStepCount READ corCaliStepCount WRITE setCorCaliStepCount NOTIFY corCaliStepCountChanged)
    Q_PROPERTY(double corCaliStepSize READ corCaliStepSize WRITE setCorCaliStepSize NOTIFY corCaliStepSizeChanged)
    Q_PROPERTY(double bhToLTCameraOffsetX READ bhToLTCameraOffsetX WRITE setBhToLTCameraOffsetX NOTIFY
                   bhToLTCameraOffsetXChanged)
    Q_PROPERTY(double bhToLTCameraOffsetY READ bhToLTCameraOffsetY WRITE setBhToLTCameraOffsetY NOTIFY
                   bhToLTCameraOffsetYChanged)
    Q_PROPERTY(double bhCorToUplookCameraOffsetX READ bhCorToUplookCameraOffsetX WRITE setBhCorToUplookCameraOffsetX
                   NOTIFY bhCorToUplookCameraOffsetXChanged)
    Q_PROPERTY(double bhCorToUplookCameraOffsetY READ bhCorToUplookCameraOffsetY WRITE setBhCorToUplookCameraOffsetY
                   NOTIFY bhCorToUplookCameraOffsetYChanged)
    Q_PROPERTY(CameraOffset *ltCameraToUplookCameraOffset READ ltCameraToUplookCameraOffset)
    Q_PROPERTY(TwoDimensionCaliParameter *ltSideTwoDimensionCalibrationParam READ ltSideTwoDimensionCalibrationParam)
    Q_PROPERTY(double ltCameraCenterXShift READ ltCameraCenterXShift WRITE setLtCameraCenterXShift NOTIFY
                   ltCameraCenterXShiftChanged)
    Q_PROPERTY(double ltCameraPrPosXShift READ ltCameraPrPosXShift WRITE setLtCameraPrPosXShift NOTIFY
                   ltCameraPrPosXShiftChanged)
    Q_PROPERTY(double stCaliGlassPrOffsetX READ stCaliGlassPrOffsetX WRITE setStCaliGlassPrOffsetX NOTIFY
                   stCaliGlassPrOffsetXChanged)
    Q_PROPERTY(double stCaliGlassPrOffsetY READ stCaliGlassPrOffsetY WRITE setStCaliGlassPrOffsetY NOTIFY
                   stCaliGlassPrOffsetYChanged)
    Q_PROPERTY(double bhToSTCameraOffsetX READ bhToSTCameraOffsetX WRITE setBhToSTCameraOffsetX NOTIFY
                   bhToSTCameraOffsetXChanged)
    Q_PROPERTY(double bhToSTCameraOffsetY READ bhToSTCameraOffsetY WRITE setBhToSTCameraOffsetY NOTIFY
                   bhToSTCameraOffsetYChanged)
    Q_PROPERTY(double stCameraCenterXShift READ stCameraCenterXShift WRITE setStCameraCenterXShift NOTIFY
                   stCameraCenterXShiftChanged)
    Q_PROPERTY(CameraOffset *stCameraToUplookCameraOffset READ stCameraToUplookCameraOffset)
    Q_PROPERTY(ConfigObjectArray *stCameraToUplookCameraOffsetOfEachRow READ stCameraToUplookCameraOffsetOfEachRow)
    Q_PROPERTY(TwoDimensionCaliParameter *stSideTwoDimensionCalibrationParam READ stSideTwoDimensionCalibrationParam)

    Q_PROPERTY(bool useLtSideTwoDimCaliData READ useLtSideTwoDimCaliData WRITE setUseLtSideTwoDimCaliData NOTIFY
                   useLtSideTwoDimCaliDataChanged)
    Q_PROPERTY(bool useStSideTwoDimCaliData READ useStSideTwoDimCaliData WRITE setUseStSideTwoDimCaliData NOTIFY
                   useStSideTwoDimCaliDataChanged)
    Q_PROPERTY(bool useCorFromCalibration READ useCorFromCalibration WRITE setUseCorFromCalibration NOTIFY
                   useCorFromCalibrationChanged)

    Q_PROPERTY(YZPos *safetyPosNearLT READ safetyPosNearLT)
    Q_PROPERTY(YZPos *safetyPosNearST READ safetyPosNearST)
    Q_PROPERTY(double ltSafetyHeightAfterPickLens READ ltSafetyHeightAfterPickLens WRITE setLtSafetyHeightAfterPickLens
                   NOTIFY ltSafetyHeightAfterPickLensChanged)
    Q_PROPERTY(double stSafetyHeightAfterPlaceLens READ stSafetyHeightAfterPlaceLens WRITE
                   setStSafetyHeightAfterPlaceLens NOTIFY stSafetyHeightAfterPlaceLensChanged)

    Q_PROPERTY(
        double higherBHZAccRatio READ higherBHZAccRatio WRITE setHigherBHZAccRatio NOTIFY higherBHZAccRatioChanged)
    Q_PROPERTY(
        double higherBHYAccRatio READ higherBHYAccRatio WRITE setHigherBHYAccRatio NOTIFY higherBHYAccRatioChanged)

    Q_PROPERTY(int delayAfterGiveUplookPrCmd READ delayAfterGiveUplookPrCmd WRITE setDelayAfterGiveUplookPrCmd NOTIFY
                   delayAfterGiveUplookPrCmdChanged)
    Q_PROPERTY(bool alignCircularLensToSensor READ alignCircularLensToSensor WRITE setAlignCircularLensToSensor NOTIFY
                   alignCircularLensToSensorChanged)

public:
    BonderHeadConfig(QObject *parent = nullptr) : ConfigObject(parent)
    {
        m_pickPlaceConfig = new PickPlaceConfig(this);
        m_safetyPosNearLT = new YZPos(this);
        m_safetyPosNearST = new YZPos(this);
        m_ltCameraToUplookCameraOffset = new CameraOffset(this);
        m_ltSideTwoDimensionCalibrationParam = new TwoDimensionCaliParameter(this);
        m_stCameraToUplookCameraOffset = new CameraOffset(this);
        m_stCameraToUplookCameraOffsetOfEachRow = new ConfigObjectArray(&CameraOffset::staticMetaObject, this);
        m_stSideTwoDimensionCalibrationParam = new TwoDimensionCaliParameter(this);
        setReadOnlyProperty("ltCaliGlassPrOffsetX");
        setReadOnlyProperty("ltCaliGlassPrOffsetY");
        setReadOnlyProperty("stCaliGlassPrOffsetX");
        setReadOnlyProperty("stCaliGlassPrOffsetY");
        init();
    }

    void resetStCameraToUplookCameraOffsetOfEachRow(int rows)
    {
        while (m_stCameraToUplookCameraOffsetOfEachRow->count() > 0)
        {
            m_stCameraToUplookCameraOffsetOfEachRow->remove(0);
        }
        for (int i = 0; i < rows; i++)
        {
            m_stCameraToUplookCameraOffsetOfEachRow->add(0);
        }
    }

    int corCaliStepCount() const
    {
        return m_corCaliStepCount;
    }

    double corCaliStepSize() const
    {
        return m_corCaliStepSize;
    }

    double bhToLTCameraOffsetX() const
    {
        return m_bhToLTCameraOffsetX;
    }

    double bhToLTCameraOffsetY() const
    {
        return m_bhToLTCameraOffsetY;
    }

    double bhToSTCameraOffsetX() const
    {
        return m_bhToSTCameraOffsetX;
    }

    double bhToSTCameraOffsetY() const
    {
        return m_bhToSTCameraOffsetY;
    }

    CameraOffset *ltCameraToUplookCameraOffset() const
    {
        return m_ltCameraToUplookCameraOffset;
    }

    CameraOffset *stCameraToUplookCameraOffset() const
    {
        return m_stCameraToUplookCameraOffset;
    }

    ConfigObjectArray *stCameraToUplookCameraOffsetOfEachRow() const
    {
        return m_stCameraToUplookCameraOffsetOfEachRow;
    }

    double ltCaliGlassPrOffsetX() const
    {
        return m_ltCaliGlassPrOffsetX;
    }

    double ltCaliGlassPrOffsetY() const
    {
        return m_ltCaliGlassPrOffsetY;
    }

    double stCaliGlassPrOffsetX() const
    {
        return m_stCaliGlassPrOffsetX;
    }

    double stCaliGlassPrOffsetY() const
    {
        return m_stCaliGlassPrOffsetY;
    }

    double corCaliStartPos() const
    {
        return m_corCaliStartPos;
    }

    bool useCorFromCalibration() const
    {
        return m_useCorFromCalibration;
    }

    double ltCameraCenterXShift() const
    {
        return m_ltCameraCenterXShift;
    }

    YZPos *safetyPosNearLT() const
    {
        return m_safetyPosNearLT;
    }

    YZPos *safetyPosNearST() const
    {
        return m_safetyPosNearST;
    }

    double stCameraCenterXShift() const
    {
        return m_stCameraCenterXShift;
    }

    double bhCorToUplookCameraOffsetX() const
    {
        return m_bhCorToUplookCameraOffsetX;
    }

    double bhCorToUplookCameraOffsetY() const
    {
        return m_bhCorToUplookCameraOffsetY;
    }

    double ltCameraPrPosXShift() const
    {
        return m_ltCameraPrPosXShift;
    }

    double ltSafetyHeightAfterPickLens() const
    {
        return m_ltSafetyHeightAfterPickLens;
    }

    TwoDimensionCaliParameter *stSideTwoDimensionCalibrationParam() const
    {
        return m_stSideTwoDimensionCalibrationParam;
    }

    bool useStSideTwoDimCaliData() const
    {
        return m_useStSideTwoDimCaliData;
    }

    TwoDimensionCaliParameter *ltSideTwoDimensionCalibrationParam() const
    {
        return m_ltSideTwoDimensionCalibrationParam;
    }

    bool useLtSideTwoDimCaliData() const
    {
        return m_useLtSideTwoDimCaliData;
    }

    double stSafetyHeightAfterPlaceLens() const
    {
        return m_stSafetyHeightAfterPlaceLens;
    }

    PickPlaceConfig *pickPlaceConfig() const
    {
        return m_pickPlaceConfig;
    }

    double higherBHZAccRatio() const
    {
        return m_higherBHZAccRatio;
    }

    double higherBHYAccRatio() const
    {
        return m_higherBHYAccRatio;
    }

    int delayAfterGiveUplookPrCmd() const
    {
        return m_delayAfterGiveUplookPrCmd;
    }

    bool alignCircularLensToSensor() const
    {
        return m_alignCircularLensToSensor;
    }

public slots:

    void setCorCaliStepCount(int corCaliStepCount)
    {
        if (m_corCaliStepCount == corCaliStepCount)
            return;

        m_corCaliStepCount = corCaliStepCount;
        emit corCaliStepCountChanged(m_corCaliStepCount);
    }

    void setCorCaliStepSize(double corCaliStepSize)
    {
        //   qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_corCaliStepSize, corCaliStepSize))
            return;

        m_corCaliStepSize = corCaliStepSize;
        emit corCaliStepSizeChanged(m_corCaliStepSize);
    }

    void setBhToLTCameraOffsetX(double bhToLTCameraOffsetX)
    {
        //    qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_bhToLTCameraOffsetX, bhToLTCameraOffsetX))
            return;

        m_bhToLTCameraOffsetX = bhToLTCameraOffsetX;
        emit bhToLTCameraOffsetXChanged(m_bhToLTCameraOffsetX);
    }

    void setBhToLTCameraOffsetY(double bhToLTCameraOffsetY)
    {
        //  qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_bhToLTCameraOffsetY, bhToLTCameraOffsetY))
            return;

        m_bhToLTCameraOffsetY = bhToLTCameraOffsetY;
        emit bhToLTCameraOffsetYChanged(m_bhToLTCameraOffsetY);
    }

    void setBhToSTCameraOffsetX(double bhToSTCameraOffsetX)
    {
        //  qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_bhToSTCameraOffsetX, bhToSTCameraOffsetX))
            return;

        m_bhToSTCameraOffsetX = bhToSTCameraOffsetX;
        emit bhToSTCameraOffsetXChanged(m_bhToSTCameraOffsetX);
    }

    void setBhToSTCameraOffsetY(double bhToSTCameraOffsetY)
    {
        //   qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_bhToSTCameraOffsetY, bhToSTCameraOffsetY))
            return;

        m_bhToSTCameraOffsetY = bhToSTCameraOffsetY;
        emit bhToSTCameraOffsetYChanged(m_bhToSTCameraOffsetY);
    }

    void setLtCaliGlassPrOffsetX(double ltCaliGlassPrOffsetX)
    {
        //  qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_ltCaliGlassPrOffsetX, ltCaliGlassPrOffsetX))
            return;

        m_ltCaliGlassPrOffsetX = ltCaliGlassPrOffsetX;
        emit ltCaliGlassPrOffsetXChanged(m_ltCaliGlassPrOffsetX);
    }

    void setLtCaliGlassPrOffsetY(double ltCaliGlassPrOffsetY)
    {
        //    qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_ltCaliGlassPrOffsetY, ltCaliGlassPrOffsetY))
            return;

        m_ltCaliGlassPrOffsetY = ltCaliGlassPrOffsetY;
        emit ltCaliGlassPrOffsetYChanged(m_ltCaliGlassPrOffsetY);
    }

    void setStCaliGlassPrOffsetX(double stCaliGlassPrOffsetX)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_stCaliGlassPrOffsetX, stCaliGlassPrOffsetX))
            return;

        m_stCaliGlassPrOffsetX = stCaliGlassPrOffsetX;
        emit stCaliGlassPrOffsetXChanged(m_stCaliGlassPrOffsetX);
    }

    void setStCaliGlassPrOffsetY(double stCaliGlassPrOffsetY)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_stCaliGlassPrOffsetY, stCaliGlassPrOffsetY))
            return;

        m_stCaliGlassPrOffsetY = stCaliGlassPrOffsetY;
        emit stCaliGlassPrOffsetYChanged(m_stCaliGlassPrOffsetY);
    }

    void setCorCaliStartPos(double corCaliStartPos)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_corCaliStartPos, corCaliStartPos))
            return;

        m_corCaliStartPos = corCaliStartPos;
        emit corCaliStartPosChanged(m_corCaliStartPos);
    }

    void setUseCorFromCalibration(bool useCorFromCalibration)
    {
        if (m_useCorFromCalibration == useCorFromCalibration)
            return;

        m_useCorFromCalibration = useCorFromCalibration;
        emit useCorFromCalibrationChanged(m_useCorFromCalibration);
    }

    void setLtCameraCenterXShift(double ltCameraCenterXShift)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_ltCameraCenterXShift, ltCameraCenterXShift))
            return;

        m_ltCameraCenterXShift = ltCameraCenterXShift;
        emit ltCameraCenterXShiftChanged(m_ltCameraCenterXShift);
    }

    void setStCameraCenterXShift(double stCameraCenterXShift)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_stCameraCenterXShift, stCameraCenterXShift))
            return;

        m_stCameraCenterXShift = stCameraCenterXShift;
        emit stCameraCenterXShiftChanged(m_stCameraCenterXShift);
    }

    void setBhCorToUplookCameraOffsetX(double bhCorToUplookCameraOffsetX)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_bhCorToUplookCameraOffsetX, bhCorToUplookCameraOffsetX))
            return;

        m_bhCorToUplookCameraOffsetX = bhCorToUplookCameraOffsetX;
        emit bhCorToUplookCameraOffsetXChanged(m_bhCorToUplookCameraOffsetX);
    }

    void setBhCorToUplookCameraOffsetY(double bhCorToUplookCameraOffsetY)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_bhCorToUplookCameraOffsetY, bhCorToUplookCameraOffsetY))
            return;

        m_bhCorToUplookCameraOffsetY = bhCorToUplookCameraOffsetY;
        emit bhCorToUplookCameraOffsetYChanged(m_bhCorToUplookCameraOffsetY);
    }

    void setLtCameraPrPosXShift(double ltCameraPrPosXShift)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_ltCameraPrPosXShift, ltCameraPrPosXShift))
            return;

        m_ltCameraPrPosXShift = ltCameraPrPosXShift;
        emit ltCameraPrPosXShiftChanged(m_ltCameraPrPosXShift);
    }

    void setLtSafetyHeightAfterPickLens(double ltSafetyHeightAfterPickLens)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_ltSafetyHeightAfterPickLens, ltSafetyHeightAfterPickLens))
            return;

        m_ltSafetyHeightAfterPickLens = ltSafetyHeightAfterPickLens;
        emit ltSafetyHeightAfterPickLensChanged(m_ltSafetyHeightAfterPickLens);
    }

    void setUseStSideTwoDimCaliData(bool useStSideTwoDimCaliData)
    {
        if (m_useStSideTwoDimCaliData == useStSideTwoDimCaliData)
            return;

        m_useStSideTwoDimCaliData = useStSideTwoDimCaliData;
        emit useStSideTwoDimCaliDataChanged(m_useStSideTwoDimCaliData);
    }

    void setUseLtSideTwoDimCaliData(bool useLtSideTwoDimCaliData)
    {
        if (m_useLtSideTwoDimCaliData == useLtSideTwoDimCaliData)
            return;

        m_useLtSideTwoDimCaliData = useLtSideTwoDimCaliData;
        emit useLtSideTwoDimCaliDataChanged(m_useLtSideTwoDimCaliData);
    }

    void setStSafetyHeightAfterPlaceLens(double stSafetyHeightAfterPlaceLens)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_stSafetyHeightAfterPlaceLens, stSafetyHeightAfterPlaceLens))
            return;

        m_stSafetyHeightAfterPlaceLens = stSafetyHeightAfterPlaceLens;
        emit stSafetyHeightAfterPlaceLensChanged(m_stSafetyHeightAfterPlaceLens);
    }

    void setHigherBHZAccRatio(double higherBHZAccRatio)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_higherBHZAccRatio, higherBHZAccRatio))
            return;

        m_higherBHZAccRatio = higherBHZAccRatio;
        emit higherBHZAccRatioChanged(m_higherBHZAccRatio);
    }

    void setHigherBHYAccRatio(double higherBHYAccRatio)
    {
        //        qWarning("Floating point comparison needs context sanity check");
        if (qFuzzyCompare(m_higherBHYAccRatio, higherBHYAccRatio))
            return;

        m_higherBHYAccRatio = higherBHYAccRatio;
        emit higherBHYAccRatioChanged(m_higherBHYAccRatio);
    }

    void setDelayAfterGiveUplookPrCmd(int delayAfterGiveUplookPrCmd)
    {
        if (m_delayAfterGiveUplookPrCmd == delayAfterGiveUplookPrCmd)
            return;

        if (delayAfterGiveUplookPrCmd < 10)
        {
            qWarning() << "delayAfterGiveUplookPrCmd must greater than 10!";
            emit delayAfterGiveUplookPrCmdChanged(m_delayAfterGiveUplookPrCmd);
            return;
        }
        m_delayAfterGiveUplookPrCmd = delayAfterGiveUplookPrCmd;
        emit delayAfterGiveUplookPrCmdChanged(m_delayAfterGiveUplookPrCmd);
    }

    void setAlignCircularLensToSensor(bool alignCircularLensToSensor)
    {
        if (m_alignCircularLensToSensor == alignCircularLensToSensor)
            return;

        m_alignCircularLensToSensor = alignCircularLensToSensor;
        emit alignCircularLensToSensorChanged(m_alignCircularLensToSensor);
    }

signals:

    void corCaliStepCountChanged(int corCaliStepCount);

    void corCaliStepSizeChanged(double corCaliStepSize);

    void bhToLTCameraOffsetXChanged(double bhToLTCameraOffsetX);

    void bhToLTCameraOffsetYChanged(double bhToLTCameraOffsetY);

    void bhToSTCameraOffsetXChanged(double bhToSTCameraOffsetX);

    void bhToSTCameraOffsetYChanged(double bhToSTCameraOffsetY);

    void ltCaliGlassPrOffsetXChanged(double ltCaliGlassPrOffsetX);

    void ltCaliGlassPrOffsetYChanged(double ltCaliGlassPrOffsetY);

    void stCaliGlassPrOffsetXChanged(double stCaliGlassPrOffsetX);

    void stCaliGlassPrOffsetYChanged(double stCaliGlassPrOffsetY);

    void corCaliStartPosChanged(double corCaliStartPos);

    void useCorFromCalibrationChanged(bool useCorFromCalibration);

    void ltCameraCenterXShiftChanged(double ltCameraCenterXShift);

    void stCameraCenterXShiftChanged(double stCameraCenterXShift);

    void bhCorToUplookCameraOffsetXChanged(double bhCorToUplookCameraOffsetX);

    void bhCorToUplookCameraOffsetYChanged(double bhCorToUplookCameraOffsetY);

    void ltCameraPrPosXShiftChanged(double ltCameraPrPosXShift);

    void ltSafetyHeightAfterPickLensChanged(double ltSafetyHeightAfterPickLens);

    void useStSideTwoDimCaliDataChanged(bool useStSideTwoDimCaliData);

    void useLtSideTwoDimCaliDataChanged(bool useLtSideTwoDimCaliData);

    void stSafetyHeightAfterPlaceLensChanged(double stSafetyHeightAfterPlaceLens);

    void higherBHZAccRatioChanged(double higherBHZAccRatio);

    void higherBHYAccRatioChanged(double higherBHYAccRatio);

    void delayAfterGiveUplookPrCmdChanged(int delayAfterGiveUplookPrCmd);

    void alignCircularLensToSensorChanged(bool alignCircularLensToSensor);

private:
    double m_corCaliStartPos = 5;
    int m_corCaliStepCount = 4;
    double m_corCaliStepSize = 20;
    double m_ltCaliGlassPrOffsetX = 0;
    double m_ltCaliGlassPrOffsetY = 0;
    double m_bhToLTCameraOffsetX = 0;
    double m_bhToLTCameraOffsetY = 0;
    double m_stCaliGlassPrOffsetX = 0;
    double m_stCaliGlassPrOffsetY = 0;
    double m_bhToSTCameraOffsetX = 0;
    double m_bhToSTCameraOffsetY = 0;
    CameraOffset *m_ltCameraToUplookCameraOffset;
    CameraOffset *m_stCameraToUplookCameraOffset;
    ConfigObjectArray *m_stCameraToUplookCameraOffsetOfEachRow;
    bool m_useCorFromCalibration = true;
    double m_ltCameraCenterXShift = 0;
    YZPos *m_safetyPosNearLT;
    YZPos *m_safetyPosNearST;
    double m_stCameraCenterXShift = 0;
    double m_bhCorToUplookCameraOffsetX = 0;
    double m_bhCorToUplookCameraOffsetY = 0;
    double m_ltCameraPrPosXShift = 0;
    double m_ltSafetyHeightAfterPickLens;
    TwoDimensionCaliParameter *m_stSideTwoDimensionCalibrationParam;
    bool m_useStSideTwoDimCaliData = false;
    TwoDimensionCaliParameter *m_ltSideTwoDimensionCalibrationParam;
    bool m_useLtSideTwoDimCaliData = false;
    double m_stSafetyHeightAfterPlaceLens = 0;
    PickPlaceConfig *m_pickPlaceConfig;
    double m_higherBHZAccRatio = 4;
    double m_higherBHYAccRatio = 4;
    int m_delayAfterGiveUplookPrCmd = 15;
    bool m_alignCircularLensToSensor = true;
};

#endif    // BONDERHEADCONFIG_H
